#include "JCAVCodecHandler.h"
#include "CCNDKLogDef.h"
#include "JCAudioPlayer.h"

#if !defined(MIN)
#define MIN(A, B) ((A) < (B) ? (A) : (B))
#endif

std::atomic<bool> m_bFileThreadRunning(false);
std::atomic<bool> m_bAudioThreadRunning(false);
std::atomic<bool> m_bVideoThreadRunning(false);
std::atomic<bool> m_bThreadRunning(false);

JCAVCodecHandler::JCAVCodecHandler()
{
    av_register_all();

    resetAllMediaPlayerParameters();
}

JCAVCodecHandler::~JCAVCodecHandler()
{
}

void JCAVCodecHandler::SetVideoFilePath(std::string &path)
{
    m_videoPathString = path;

    std::string fileSuffix = getFileSuffix(m_videoPathString.c_str());
    LOGD("File suffix %s", fileSuffix.c_str());
    if (fileSuffix == "mp3")
    {
        m_mediaType = MEDIATYPE_MUSIC;
    }
    else
    {
        m_mediaType = MEDIATYPE_VIDEO;
    }
}

std::string JCAVCodecHandler::GetVideoFilePath()
{
    return m_videoPathString;
}

int JCAVCodecHandler::GetVideoWidth()
{
    return m_videoWidth;
}

int JCAVCodecHandler::GetVideoHeight()
{
    return m_videoHeight;
}

void JCAVCodecHandler::SetupUpdateVideoCallback(UpdateVideo2GUI_Callback callback, unsigned long userData)
{
    m_updateVideoCallback = callback;
    m_userDataVideo = userData;
}

void JCAVCodecHandler::SetupUpdateCurrentPTSCallback(UpdateCurrentPTS_Callback callback, unsigned long userData)
{
    m_updateCurrentPTSCallback = callback;
    m_userDataPts = userData;
}

// 市面上的音视频有几种情况 完善的播放器,需要做处理。
// 1 有视频，有音频 m_pVideoCodecCtx != NULL m_pAudioCodecCtx != NULL 用音频同步视频
// 2 有视频，没音频 m_pVideoCodecCtx != NULL m_pAudioCodecCtx == NULL 按照视频FPS自己播放
// 3 有封面的mp3 同1 但只有一张封面图片，当作视频，相当于只有一帧视频.
// 4 没有封面的mp3 盗版音乐 m_pVideoCodecCtx == NULL m_pAudioCodecCtx != NULL
int JCAVCodecHandler::InitVideoCodec()
{
    if (m_videoPathString == "")
    {
        LOGF("file path is Empty...");
        return -1;
    }

    const char *filePath = m_videoPathString.c_str();

    if (avformat_open_input(&m_pFormatCtx, filePath, NULL, NULL) != 0)
    {
        LOGF("open input stream failed .");
        return -1;
    }

    if (avformat_find_stream_info(m_pFormatCtx, nullptr) < 0)
    {
        LOGF("avformat_find_stream_info failed .");
        return -1;
    }

    av_dump_format(m_pFormatCtx, 0, filePath, 0);

    m_videoStreamIdx = -1;
    m_audioStreamIdx = -1;

    for (int i = 0; i < (int)m_pFormatCtx->nb_streams; ++i)
    {
        AVCodecParameters *codecParameters = m_pFormatCtx->streams[i]->codecpar;

        if (codecParameters->codec_type == AVMEDIA_TYPE_VIDEO)
        {
            m_videoStreamIdx = i;
            LOGF("video index: %d", m_videoStreamIdx);

            AVCodec *codec = avcodec_find_decoder(codecParameters->codec_id);
            if (codec == nullptr)
            {
                LOGF("Video AVCodec is NULL");
                return -1;
            }

            m_pVideoCodecCtx = avcodec_alloc_context3(codec);
            avcodec_parameters_to_context(m_pVideoCodecCtx, codecParameters);

            if (avcodec_open2(m_pVideoCodecCtx, codec, NULL) < 0)
            {
                LOGF("Could not open codec.");
                return -1;
            }
        }
        else if (codecParameters->codec_type == AVMEDIA_TYPE_AUDIO)
        {
            m_audioStreamIdx = i;
            LOGF("Audio index: %d", m_audioStreamIdx);

            AVCodec *codec = avcodec_find_decoder(codecParameters->codec_id);
            if (codec == nullptr)
            {
                LOGF("Audo AVCodec is NULL");
                return -1;
            }

            m_pAudioCodecCtx = avcodec_alloc_context3(codec);
            avcodec_parameters_to_context(m_pAudioCodecCtx, codecParameters);

            if (avcodec_open2(m_pAudioCodecCtx, codec, NULL) < 0)
            {
                LOGF("audio decoder not found.");
                return -1;
            }

            m_sampleRate = m_pAudioCodecCtx->sample_rate;
            m_channel = m_pAudioCodecCtx->channels;
            switch (m_pAudioCodecCtx->sample_fmt)
            {
            case AV_SAMPLE_FMT_U8:
                m_sampleSize = 8;
            case AV_SAMPLE_FMT_S16:
                m_sampleSize = 16;
                break;
            case AV_SAMPLE_FMT_S32:
                m_sampleSize = 32;
                break;
            default:
                break;
            }
        }
    }

    JCAudioPlayer::GetInstance()->SetSampleRate(m_sampleRate);
    JCAudioPlayer::GetInstance()->SetSampleSize(m_sampleSize);
    JCAudioPlayer::GetInstance()->Setchannel(m_channel);

    if (m_pVideoCodecCtx != NULL)
    {
        // 分配一个 AVFrame 对象m_pYUVFrame，AVFrame 是一个结构体，用于存储视频帧的像素数据
        // 这是1个管理视频帧数据的结构，真正的视频帧数据，存放到了下面的m_pYUV420Buffer中
        m_pYUVFrame = av_frame_alloc();
        if (m_pYUVFrame == NULL)
        {
            LOGF("YUV frame alloc error.");
            return -1;
        }

        // 为存储 YUV420P 格式数据分配内存，真正的视频数据存放到了这里
        m_pYUV420Buffer = (uint8_t *)av_malloc(av_image_get_buffer_size(AV_PIX_FMT_YUV420P, m_pVideoCodecCtx->width, m_pVideoCodecCtx->height, 1));
        if (m_pYUV420Buffer == NULL)
        {
            LOGF("out buffer alloc error.");
            return -1;
        }

        // av_image_fill_arrays() 函数将填充 AVFrame 对象（即 m_pYUVFrame）的 data 和 linesize 字段。它将视频帧数据（m_pYUV420Buffer）映射到 m_pYUVFrame 结构中：
        // m_pYUVFrame->data：表示一个指向 YUV 数据平面的指针数组（Y、U、V）。
        // m_pYUVFrame->linesize：每个平面数据的行大小。
        // m_pYUV420Buffer：分配的内存区域，它存储了 YUV420P 数据。
        // AV_PIX_FMT_YUV420P：指定像素格式为 YUV420P。
        // m_pVideoCodecCtx->width 和 m_pVideoCodecCtx->height：视频帧的宽度和高度。
        // 1：用于指示图像有多少个平面数据（YUV420P 有 3 个平面：Y、U、V）。
        // 这行代码的目的是将缓冲区 m_pYUV420Buffer 中的 YUV 数据映射到 m_pYUVFrame 的 data 和 linesize 字段，便于后续的图像处理。
        av_image_fill_arrays(m_pYUVFrame->data, m_pYUVFrame->linesize, m_pYUV420Buffer, AV_PIX_FMT_YUV420P, m_pVideoCodecCtx->width, m_pVideoCodecCtx->height, 1);

        m_videoWidth = m_pVideoCodecCtx->width;
        m_videoHeight = m_pVideoCodecCtx->height;

        LOGD("Init VideoCodec sucess. Width: %d Height: %d", m_videoWidth, m_videoHeight);
    }

    if (m_videoStreamIdx != -1)
    {
        AVStream *videoStream = m_pFormatCtx->streams[m_videoStreamIdx];
        m_videoStreamTimeRational = videoStream->time_base;
        m_videoFPS = videoStream->avg_frame_rate.num / videoStream->avg_frame_rate.den;
        LOGD("Init VideoCodec sucess.V Time Base: %d  Den :%d", videoStream->time_base.num, videoStream->time_base.den);
    }

    if (m_audioStreamIdx != -1)
    {
        AVStream *audioStream = m_pFormatCtx->streams[m_audioStreamIdx];
        m_audioStreamTimeRational = audioStream->time_base;
        LOGD("Init VideoCodec sucess.A Time Base: %d Den  %d", audioStream->time_base.num, audioStream->time_base.den);
    }
    return 0;
}

void JCAVCodecHandler::StartPlayVideo()
{
    JCAudioPlayer::GetInstance()->StartAudioPlayer();

    startMediaProcessThreads();
}

void JCAVCodecHandler::StopPlayVideo()
{
    m_bThreadRunning = false;

    m_bReadFileEOF = false;

    m_nCurrAudioTimeStamp = 0.0f;
    m_nLastAudioTimeStamp = 0.0f;

    m_videoStreamTimeRational = av_make_q(0, 0);
    m_audioStreamTimeRational = av_make_q(0, 0);

    m_eMediaPlayStatus = MEDIAPLAY_STATUS_STOP;

    JCAudioPlayer::GetInstance()->StopAudioPlayer();

    while (!m_audioPktQueue.isEmpty())
    {
        // 使用unique_ptr的自定义删除器，执行av_packet_free(&pkt)释放队列中的packet
        std::unique_ptr<AVPacket, void (*)(AVPacket *)> packet((AVPacket *)m_audioPktQueue.dequeue(), [](AVPacket *pkt) {
            if (pkt) {
                av_packet_free(&pkt);
            } 
        });
    }

    while (!m_videoPktQueue.isEmpty())
    {
        // 使用unique_ptr的自定义删除器，执行av_packet_free(&pkt)释放队列中的packet
        std::unique_ptr<AVPacket, void (*)(AVPacket *)> packet((AVPacket *)m_videoPktQueue.dequeue(), [](AVPacket *pkt) {
            if (pkt) {
                av_packet_free(&pkt);
            } 
        });
    }

    waitAllThreadsExit();

    UnInitVideoCodec();

    resetAllMediaPlayerParameters();

    LOGD("======STOP PLAY VIDEO SUCCESS========");
}

void JCAVCodecHandler::startMediaProcessThreads()
{
    m_bThreadRunning = true;

    std::thread readThread(&JCAVCodecHandler::doReadMediaFrameThread, this);
    readThread.detach();

    std::thread audioThread(&JCAVCodecHandler::doAudioDecodePlayThread, this);
    audioThread.detach();

    std::thread videoThread(&JCAVCodecHandler::doVideoDecodeShowThread, this);
    videoThread.detach();


}

void JCAVCodecHandler::SeekMedia(float nPos)
{
    if (nPos < 0)
    {
        return;
    }
    if (m_pFormatCtx == nullptr)
    {
        return;
    }

    m_bThreadRunning = false;
    m_bReadFileEOF = false;

    if (m_mediaType == MEDIATYPE_VIDEO)
    {

        m_nSeekingPos = (long long)nPos / av_q2d(m_videoStreamTimeRational);

        if (m_audioStreamIdx >= 0 && m_videoStreamIdx >= 0 || m_audioStreamIdx < 0 && m_videoStreamIdx >= 0)
        {
            av_seek_frame(m_pFormatCtx, m_videoStreamIdx, m_nSeekingPos, AVSEEK_FLAG_BACKWARD);
        }
    }

    if (m_mediaType == MEDIATYPE_MUSIC)
    {
        LOGD("SEEK AUDIO");
        m_nSeekingPos = (int64)nPos / av_q2d(m_audioStreamTimeRational);
        if (m_audioStreamIdx >= 0)
        {
            av_seek_frame(m_pFormatCtx, m_audioStreamIdx, m_nSeekingPos, AVSEEK_FLAG_ANY);
        }
    }

    while (!m_videoPktQueue.isEmpty())
    {
        // 使用unique_ptr的自定义删除器，执行av_packet_free(&pkt)释放队列中的packet
        std::unique_ptr<AVPacket, void (*)(AVPacket *)> packet((AVPacket *)m_videoPktQueue.dequeue(), [](AVPacket *pkt) {
            if (pkt) {
                av_packet_free(&pkt);
            }
        });
    }

    while (!m_audioPktQueue.isEmpty())
    {
        // 使用unique_ptr的自定义删除器，执行av_packet_free(&pkt)释放队列中的packet
        std::unique_ptr<AVPacket, void (*)(AVPacket *)> packet((AVPacket *)m_audioPktQueue.dequeue(), [](AVPacket *pkt) {
            if (pkt) {
                av_packet_free(&pkt);
            } 
        });
    }

    waitAllThreadsExit();

    startMediaProcessThreads();
}

void JCAVCodecHandler::waitAllThreadsExit()
{
    while (m_bFileThreadRunning)
    {
        stdThreadSleep(10);
        continue;
    }

    while (m_bAudioThreadRunning)
    {
        stdThreadSleep(10);
        continue;
    }

    while (m_bVideoThreadRunning)
    {
        stdThreadSleep(10);
        continue;
    }
}

float JCAVCodecHandler::GetMediaTotalSeconds()
{
    float totalDuration = m_pFormatCtx->duration / (AV_TIME_BASE * 1.000);
    return totalDuration;
}

void JCAVCodecHandler::SetMediaStatusPlay()
{
    m_eMediaPlayStatus = MEDIAPLAY_STATUS_PLAYING;
}

void JCAVCodecHandler::SetMediaStatusPause()
{
    m_eMediaPlayStatus = MEDIAPLAY_STATUS_PAUSE;
}

int JCAVCodecHandler::GetPlayerStatus()
{
    return m_eMediaPlayStatus;
}

void JCAVCodecHandler::tickVideoFrameTimerDelay(int64_t pts)
{
    if (m_videoStreamTimeRational.den <= 0)
    {
        return;
    }

    float currVideoTimeStamp = pts * av_q2d(m_videoStreamTimeRational);

    // 没有音频数据，只有视频数据，所以不需要做音视频同步操作
    if (m_pAudioCodecCtx == NULL)
    {
        float sleepTime = 1000.0 / (float)m_videoFPS;
        stdThreadSleep((int)sleepTime);

        if (m_updateCurrentPTSCallback)
        {
            m_updateCurrentPTSCallback(currVideoTimeStamp, m_userDataPts);
        }

        return;
    }
    // 使用视频时间戳currVideoTimeStamp - 音频时间戳m_nCurrAudioTimeStamp = 表示音视频同步时，以音频播放时间戳为基准，将视频同步到音频
    float diffTime = (currVideoTimeStamp - m_nCurrAudioTimeStamp) * 1000;

    int sleepTime = (int)diffTime;

    // LOGD("A TimeStamp: %f",m_nCurrAudioTimeStamp);
    // LOGD("AT: %f VT: %f ST: %d ",m_nCurrAudioTimeStamp,currVideoTimeStamp,sleepTime);

    if (sleepTime > 0 && sleepTime < 5000)
    {
        stdThreadSleep(sleepTime);
    }
    else
    {
        // stdThreadSleep(0);
    }
}

void JCAVCodecHandler::tickAudioFrameTimerDelay(int64_t pts)
{
    if (m_audioStreamTimeRational.den <= 0)
    {
        return;
    }

    m_nCurrAudioTimeStamp = pts * av_q2d(m_audioStreamTimeRational);

    int diffTime = (int)(m_nCurrAudioTimeStamp - m_nLastAudioTimeStamp);

    if (abs(diffTime) >= 1)
    {
        if (m_updateCurrentPTSCallback)
        {
            m_updateCurrentPTSCallback(m_nCurrAudioTimeStamp, m_userDataPts);
        }

        m_nLastAudioTimeStamp = m_nCurrAudioTimeStamp;
    }

    return;
}

void JCAVCodecHandler::doReadMediaFrameThread()
{
    while (m_bThreadRunning)
    {
        m_bFileThreadRunning = true;

        if (m_eMediaPlayStatus == MEDIAPLAY_STATUS_PAUSE)
        {
            stdThreadSleep(10);
            continue;
        }

        if (m_pVideoCodecCtx != NULL && m_pAudioCodecCtx != NULL)
        { // 有视频,有音频

            if (m_videoPktQueue.size() > MAX_VIDEO_FRAME_IN_QUEUE && m_audioPktQueue.size() > MAX_AUDIO_FRAME_IN_QUEUE)
            {
                stdThreadSleep(10);
                continue;
            }
        }
        else if (m_pVideoCodecCtx != NULL && m_pAudioCodecCtx == NULL)
        { // 只有视频,没有音频

            float sleepTime = 1000.0 / (float)m_videoFPS;
            stdThreadSleep((int)sleepTime);
        }
        else
        { // 只有音频
            if (m_videoPktQueue.size() > MAX_AUDIO_FRAME_IN_QUEUE)
            {
                stdThreadSleep(10);
                continue;
            }
        }

        if (m_bReadFileEOF == false)
        {
            // 读取mp4文件解封装后，经过压缩的，音频和视频数据
            readMediaPacket();
        }
        else
        {
            // m_bThreadRunning = false;
            stdThreadSleep(10);
        }
    }

    LOGD("read file thread exit...");

    m_bFileThreadRunning = false;

    return;
}

void JCAVCodecHandler::readMediaPacket()
{
    // 为AVPacket分配内存并自动管理释放
    std::unique_ptr<AVPacket, void (*)(AVPacket *)> packet(av_packet_alloc(), [](AVPacket *pkt) {
        if (pkt) {
            av_packet_free(&pkt);
        } 
    });

    if (!packet)
    {
        return;
    }

    av_init_packet(packet.get());
    m_eMediaPlayStatus = MEDIAPLAY_STATUS_PLAYING;

    int retValue = av_read_frame(m_pFormatCtx, packet.get());
    if (retValue < 0)
    {
        if (retValue == AVERROR_EOF && !m_bReadFileEOF)
        {
            m_bReadFileEOF = true;
        }
        return;
    }

    // 判断packet是否为视频或音频流
    if (packet->stream_index == m_videoStreamIdx || packet->stream_index == m_audioStreamIdx)
    {
        if (!av_dup_packet(packet.get()))
        {
            // 复制packet数据
            // 根据流类型将packet放入相应的队列
            if (packet->stream_index == m_videoStreamIdx)
            {
                m_lastVideoPts = packet->pts;
                //  unique_ptr::release()：
                //  release()函数的作用是释放所有权，返回指针的原始裸指针，并将unique_ptr内部的指针置为nullptr。
                //  调用release()后，unique_ptr不再负责管理也不再自动释放资源。这意味着自定义删除器不会被调用，因为unique_ptr认为自己不再拥有该资源。
                //  自定义删除器的执行：
                //  在正常情况下，当unique_ptr超出作用域或被重置时，会调用其关联的删除器来释放资源。在调用release()之后，由于unique_ptr主动放弃了对资源的管理，删除器自然也不会被调用。
                //  当执行m_videoPktQueue.enqueue(packet.release());时，unique_ptr的自定义删除器av_packet_free(&pkt);将不会执行，因为所有权已经交给队列，由队列负责后续的资源管理和释放。
                m_videoPktQueue.enqueue(packet.release());
            }
            else if (packet->stream_index == m_audioStreamIdx)
            {
                m_audioPktQueue.enqueue(packet.release());
            }
        }
    }
}

float JCAVCodecHandler::getVideoTimeStampFromPTS(int64 pts)
{
    float vTimeStamp = pts * av_q2d(m_videoStreamTimeRational);
    return vTimeStamp;
}

float JCAVCodecHandler::getAudioTimeStampFromPTS(int64 pts)
{
    float aTimeStamp = pts * av_q2d(m_audioStreamTimeRational);
    return aTimeStamp;
}

void JCAVCodecHandler::doAudioDecodePlayThread()
{
    if (m_pFormatCtx == NULL)
    {
        return;
    }

    if (m_pAudioFrame == NULL)
    {
        m_pAudioFrame = av_frame_alloc();
    }

    while (m_bThreadRunning)
    {
        m_bAudioThreadRunning = true;

        if (m_eMediaPlayStatus == MEDIAPLAY_STATUS_PAUSE)
        {
            stdThreadSleep(10);
            continue;
        }

        if (m_audioPktQueue.isEmpty())
        {
            stdThreadSleep(1);
            continue;
        }

        std::unique_ptr<AVPacket, void (*)(AVPacket *)> pkt((AVPacket *)m_audioPktQueue.dequeue(), [](AVPacket *pkt) {
            if (pkt) {
                av_packet_free(&pkt);
            } 
        });

        if (!pkt)
        {
            break;
        }

        if (!m_bThreadRunning)
        {
            break;
        }

        tickAudioFrameTimerDelay(pkt->pts);
        // 将pkt中存放的音频压缩数据，放到音频解码器中，进行解码，也就是解压缩
        int retValue = avcodec_send_packet(m_pAudioCodecCtx, pkt.get());
        if (retValue != 0)
        {
            continue;
        }
        // 从音频解码器中获取解码后的音频数据，存放到m_pAudioFrame中
        int decodeRet = avcodec_receive_frame(m_pAudioCodecCtx, m_pAudioFrame);
        if (decodeRet == 0)
        {
            // 将解码后的音频数据m_pAudioFrame，放到opensl中进行播放
            convertAndPlayAudio(m_pAudioFrame);
        }
    }

    LOGD("audio decode show  thread exit...");

    m_bAudioThreadRunning = false;

    return;
}

void JCAVCodecHandler::convertAndPlayAudio(AVFrame *decodedFrame)
{
    if (!m_pFormatCtx || !m_pAudioFrame || !decodedFrame)
    {
        return;
    }

    if (m_pAudioSwrCtx == NULL) {
        m_pAudioSwrCtx = swr_alloc(); // 分配SwrContext内存

        // 设置音频重采样上下文的选项
        swr_alloc_set_opts(
            m_pAudioSwrCtx,
            av_get_default_channel_layout(m_channel), // 输出通道布局（如立体声）
            AV_SAMPLE_FMT_S16,                        // 输出采样格式（16位有符号整数）
            m_sampleRate,                             // 输出采样率（如44100Hz）（需与播放设备匹配）
            av_get_default_channel_layout(m_pAudioCodecCtx->channels), // 输入通道布局，m_pAudioCodecCtx->channels表示：解码后的原始音频通道数
            m_pAudioCodecCtx->sample_fmt,             // 输入采样格式（解码器输出的格式，解码后的原始采样格式（如FLTP、S16P等））
            m_pAudioCodecCtx->sample_rate,            // 输入采样率（解码器输出的采样率，解码后的原始采样率）
            0, NULL                                   // 最后两个参数通常用于传递与重采样相关的附加选项，这里使用默认值。
        );

        if (m_pAudioSwrCtx != NULL) {
            if (swr_init(m_pAudioSwrCtx) < 0) {// 初始化重采样器
                swr_free(&m_pAudioSwrCtx);
                return;
            }
        }
    }
    // 计算重采样后的音频数据所需缓冲区大小，并按需扩展缓冲区
    // 示例：
    //    参数：
    //        nb_channels = 2（立体声）
    //        nb_samples = 1024（每帧采样数）
    //        sample_fmt = AV_SAMPLE_FMT_S16（16位有符号整数）
    //        align = 0（默认对齐）
    //    计算步骤：
    //        每个样本的字节数： AV_SAMPLE_FMT_S16 是16位（2字节），因此每个样本占 2字节。
    //        总字节数： 声道数 × 样本数 × 字节/样本 = 2 × 1024 × 2 = 4096字节。
    //    结果：
    //    缓冲区大小为 4096字节。
    int bufSize = av_samples_get_buffer_size(
        NULL,                    // 不返回每通道大小
        m_channel,               // 输出通道数
        decodedFrame->nb_samples,// 输入样本数（假设输入/输出采样率相同）
        AV_SAMPLE_FMT_S16,       // 输出采样格式
        0                        // 对齐方式（默认）
    );

    if (!m_pSwrBuffer || m_swrBuffSize < bufSize)
    {
        m_swrBuffSize = bufSize;// 更新缓冲区大小
        m_pSwrBuffer = (uint8_t *)realloc(m_pSwrBuffer, m_swrBuffSize);// 重新分配缓冲区
    }

    // 创建一个指向输出缓冲区的指针数组 outbuf，该数组包含两个指针：
    // outbuf[0]指向重采样缓冲区。
    // outbuf[1] 设置为 0，表示第二个输出。如果只使用单声道输出，第一个输出缓冲区即可。
    uint8_t *outbuf[2] = {m_pSwrBuffer, 0};

    // 执行重采样
    int len = swr_convert(
        m_pAudioSwrCtx,                       // 音频重采样上下文
        outbuf,                               // 输出缓冲区，由上面准备的指针数组组成
        decodedFrame->nb_samples,             // 输出采样数
        (const uint8_t **)decodedFrame->data, //  输入音频帧的数据，它是一个指向音频分量数据的数组
        decodedFrame->nb_samples              // 输入采样数
    );
    if (len <= 0)
    {
        return;
    }

    if (!m_bThreadRunning)
    {
        return;
    }
    // 将转换后的音频数据（PCM）传递给音频播放器进行实时播放
    JCAudioPlayer::GetInstance()->WriteAudioData((const char *)m_pSwrBuffer, bufSize);
}

void JCAVCodecHandler::doVideoDecodeShowThread()
{
    if (m_pFormatCtx == NULL)
    {
        return;
    }

    if (m_pVideoFrame == NULL)
    {
        m_pVideoFrame = av_frame_alloc();
    }

    while (m_bThreadRunning)
    {
        m_bVideoThreadRunning = true;

        if (m_eMediaPlayStatus == MEDIAPLAY_STATUS_PAUSE)
        {
            stdThreadSleep(10);
            continue;
        }

        if (m_videoPktQueue.isEmpty())
        {
            stdThreadSleep(1);
            continue;
        }

        std::unique_ptr<AVPacket, void (*)(AVPacket *)> pkt((AVPacket *)m_videoPktQueue.dequeue(), [](AVPacket *pkt) {
            if (pkt) {
                av_packet_free(&pkt);
            } 
        });
        if (!pkt)
        {
            break;
        }

        if (!m_bThreadRunning)
        {
            break;
        }

        // 使用视频时间戳currVideoTimeStamp - 音频时间戳m_nCurrAudioTimeStamp = 表示音视频同步时，以音频播放时间戳为基准，将视频同步到音频
        tickVideoFrameTimerDelay(pkt->pts);

        // 将pkt中存放的视频压缩数据，放到视频解码器中，进行解码，也就是解压缩
        int retValue = avcodec_send_packet(m_pVideoCodecCtx, pkt.get());
        if (retValue != 0)
        {
            continue;
        }
        // 从视频解码器中获取解码后的视频数据，存放到m_pVideoFrame中
        int decodeRet = avcodec_receive_frame(m_pVideoCodecCtx, m_pVideoFrame);
        if (decodeRet == 0)
        {
            // 将解码后的视频数据，放到opengl中进行视频帧渲染
            convertAndRenderVideo(m_pVideoFrame, pkt->pts);
        }
        if (m_enableLoopPlay && m_lastVideoPts == pkt->pts) {
            std::thread([this]() {
                SeekMedia(0);
            }).detach();
            m_lastVideoPts = AV_NOPTS_VALUE;
        }
    }

    LOGD("video decode show  thread exit...");

    m_bVideoThreadRunning = false;

    return;
}

void JCAVCodecHandler::convertAndRenderVideo(AVFrame *videoFrame, long long ppts)
{
    if (videoFrame == NULL)
    {
        return;
    }

    if (m_pVideoSwsCtx == NULL)
    {
        // 作用：创建或获取一个图像处理上下文（SwsContext），用于管理缩放和像素格式转换的配置。
        // 关键参数：
        // 输入/输出宽高相同，说明不需要缩放，仅进行格式转换。
        // AV_PIX_FMT_YUV420P：目标格式，这是视频编码和传输中最常用的格式（如H.264、MPEG）。
        // SWS_BICUBIC：插值算法，在图像质量与性能间平衡，适合无明显锯齿的场景。
        m_pVideoSwsCtx = sws_getContext(
            m_pVideoCodecCtx->width,   // 输入图像的宽度
            m_pVideoCodecCtx->height,  // 输入图像的高度
            m_pVideoCodecCtx->pix_fmt, // 输入图像的像素格式（如RGB24、NV12等）
            m_pVideoCodecCtx->width,   // 输出图像的宽度（与输入相同，无缩放）
            m_pVideoCodecCtx->height,  // 输出图像的高度（与输入相同，无缩放）
            AV_PIX_FMT_YUV420P,        // 输出图像的像素格式（强制转为YUV420P）
            SWS_BICUBIC,               // 缩放算法（双三次插值，质量较高）
            NULL, NULL, NULL           // 其他参数（默认）
        );
    }
    // 将输入图像（videoFrame）转换为目标格式（YUV420P），并写入输出帧（m_pYUVFrame）
    sws_scale(
        m_pVideoSwsCtx,                          // 先前初始化的 SWS 上下文，用于指定转换时的设置
        (const uint8_t *const *)videoFrame->data,// 输入图像的数据指针数组，指向编码视频帧的原始数据。videoFrame->data 包含指向图像每个分量的指针（Y、U、V），因此需要转换为 const uint8_t *const * 类型
        videoFrame->linesize,                    // 输入图像的行大小数组，指定每个分量在内存中每行的字节大小。
        0,                                       // 输入图像的起始行（通常为 0，表示从第一行开始处理）。
        m_pVideoCodecCtx->height,                // 输入图像的高度，用于计算处理的行数。
        m_pYUVFrame->data,                       // 输出图像数据的指针数组，指向目标 YUV 帧的数据缓冲区，转换后图像将被填充到这里。
        m_pYUVFrame->linesize                    // 输出图像的行大小数组，指定每个分量在内存中每行的字节大小。
    );

    unsigned int lumaLength = m_pVideoCodecCtx->height * (MIN(videoFrame->linesize[0], m_pVideoCodecCtx->width));
    unsigned int chromBLength = ((m_pVideoCodecCtx->height) / 2) * (MIN(videoFrame->linesize[1], (m_pVideoCodecCtx->width) / 2));
    unsigned int chromRLength = ((m_pVideoCodecCtx->height) / 2) * (MIN(videoFrame->linesize[2], (m_pVideoCodecCtx->width) / 2));

    std::unique_ptr<YUVData_Frame> updateYUVFrame = std::make_unique<YUVData_Frame>();

    updateYUVFrame->luma.length = lumaLength;
    updateYUVFrame->chromaB.length = chromBLength;
    updateYUVFrame->chromaR.length = chromRLength;

    updateYUVFrame->luma.dataBuffer = std::make_unique<unsigned char[]>(lumaLength);
    updateYUVFrame->chromaB.dataBuffer = std::make_unique<unsigned char[]>(chromBLength);
    updateYUVFrame->chromaR.dataBuffer = std::make_unique<unsigned char[]>(chromRLength);

    copyDecodedFrame420(m_pYUVFrame->data[0], updateYUVFrame->luma.dataBuffer.get(), m_pYUVFrame->linesize[0],
                        m_pVideoCodecCtx->width, m_pVideoCodecCtx->height);
    copyDecodedFrame420(m_pYUVFrame->data[1], updateYUVFrame->chromaB.dataBuffer.get(), m_pYUVFrame->linesize[1],
                        m_pVideoCodecCtx->width / 2, m_pVideoCodecCtx->height / 2);
    copyDecodedFrame420(m_pYUVFrame->data[2], updateYUVFrame->chromaR.dataBuffer.get(), m_pYUVFrame->linesize[2],
                        m_pVideoCodecCtx->width / 2, m_pVideoCodecCtx->height / 2);

    updateYUVFrame->width = m_pVideoCodecCtx->width;
    updateYUVFrame->height = m_pVideoCodecCtx->height;

    updateYUVFrame->pts = ppts;

    if(m_updateVideoCallback)
    {
        m_updateVideoCallback(updateYUVFrame.get(), m_userDataVideo);
    }
}


void JCAVCodecHandler::copyDecodedFrame420(uint8_t *src, uint8_t *dist, int linesize, int width, int height)
{
    width = MIN(linesize, width);
    for (int i = 0; i < height; ++i)
    {
        memcpy(dist, src, width);
        dist += width;
        src += linesize;
    }
}

void JCAVCodecHandler::copyDecodedFrame(uint8_t *src, uint8_t *dist, int linesize, int width, int height)
{
    width = MIN(linesize, width);

    for (int i = 0; i < height; ++i)
    {
        memcpy(dist, src, width);
        dist += width;
        src += linesize;
    }
}

void JCAVCodecHandler::UnInitVideoCodec()
{
    LOGD("UnInitVideoCodec...");

    if (m_pSwrBuffer != NULL)
    {

        free(m_pSwrBuffer);
    }

    if (m_pAudioSwrCtx != NULL)
    {
        swr_free(&m_pAudioSwrCtx);
    }

    if (m_pAudioFrame != NULL)
    {
        av_frame_free(&m_pAudioFrame);
    }

    if (m_pAudioCodecCtx != NULL)
    {
        avcodec_close(m_pAudioCodecCtx);
    }

    if (m_pYUV420Buffer != NULL)
    {
        av_free(m_pYUV420Buffer);
    }

    if (m_pYUVFrame != NULL)
    {
        av_frame_free(&m_pYUVFrame);
    }

    if (m_pVideoSwsCtx != NULL)
    {
        sws_freeContext(m_pVideoSwsCtx);
    }

    if (m_pVideoFrame != NULL)
    {
        av_frame_free(&m_pVideoFrame);
    }

    if (m_pVideoCodecCtx != NULL)
    {
        avcodec_close(m_pVideoCodecCtx);
    }

    if (m_pFormatCtx != NULL)
    {
        avformat_close_input(&m_pFormatCtx);
    }
}

void JCAVCodecHandler::stdThreadSleep(int mseconds)
{
    std::chrono::milliseconds sleepTime(mseconds);
    std::this_thread::sleep_for(sleepTime);
}

void JCAVCodecHandler::resetAllMediaPlayerParameters()
{
    m_pFormatCtx = NULL;
    m_pVideoCodecCtx = NULL;
    m_pAudioCodecCtx = NULL;
    m_pYUVFrame = NULL;
    m_pVideoFrame = NULL;
    m_pAudioFrame = NULL;
    m_pAudioSwrCtx = NULL;
    m_pVideoSwsCtx = NULL;
    m_pYUV420Buffer = NULL;
    m_pSwrBuffer = NULL;

    m_videoWidth = 0;
    m_videoHeight = 0;

    m_videoPathString = "";

    m_videoStreamIdx = -1;
    m_audioStreamIdx = -1;

    m_bReadFileEOF = false;

    m_nSeekingPos = 0;

    m_nCurrAudioTimeStamp = 0.0f;
    m_nLastAudioTimeStamp = 0.0f;

    m_sampleRate = 48000;
    m_sampleSize = 16;
    m_channel = 2;

    m_volumeRatio = 1.0f;
    m_swrBuffSize = 0;

    m_videoStreamTimeRational = av_make_q(0, 0);
    m_audioStreamTimeRational = av_make_q(0, 0);

    m_mediaType = MEDIATYPE_VIDEO;
    m_eMediaPlayStatus = MEDIAPLAY_STATUS_STOP;
}

std::string JCAVCodecHandler::getFileSuffix(const char *path)
{
    const char *pos = strrchr(path, '.');
    if (pos)
    {
        std::string str(pos + 1);
        std::transform(str.begin(), str.end(), str.begin(), ::tolower);
        return str;
    }
    return std::string();
}